#include "CBL_Memory.h"

CB_SUBNAMESPACE_START(Memory)

// -------------------------------------------------------------------------------------------------

//! /note	Tries to allocate memory so that memory fragmentation is kept at a low level.
//!			This will create larger allocations than necessary as it will always try to allocate
//!			The next higher power of two number of bytes if the allocation size is below 32KB.
void* AllocLowFragemtation(memint _Size)
{
    static const memint MaxBucketSize = 32768;
    if (_Size < MaxBucketSize)
		_Size = Math::NextPowerOf2(_Size);
	
	return ::operator new(_Size);
}

// -------------------------------------------------------------------------------------------------

//! /note	Allocates memory aligned to _Alignment Bytes. So if _Alignment is 128, the pointer adress returned
//!			modulo 128 will be 0.
//!			The allocated size will always bei _Size + _Alignment, offset information will be stored one 
//!			byte before the returned adress.
void* AllocAligned(memint _Size, uint8 _Alignment)
{
	void* pMemory = ::operator new(_Size + _Alignment);
    memint BaseAdress = (memint)reinterpret_cast<size_t>(pMemory);
	
	uint8 Offset = static_cast<uint8>(BaseAdress % _Alignment);
	if (Offset == 0) Offset = _Alignment;
	
	uint8* pBytePtr = reinterpret_cast<uint8*>(pMemory);
	
	pBytePtr += Offset-1;
	*pBytePtr = Offset;
	++pBytePtr;
	
	return pBytePtr;
}

// -------------------------------------------------------------------------------------------------

//! /note	Deallocates aligned memory
void DeAllocAligned(void* _pObject)
{
	uint8* pBytePtr = reinterpret_cast<uint8*>(_pObject);
	uint8 Offset =* (pBytePtr-1);
	pBytePtr -= Offset;
	
	::operator delete(pBytePtr);
}

// -------------------------------------------------------------------------------------------------

//!	/note	Like AllocAligned, only for arrays.
void* ArrayAllocAligned(memint _Size, uint8 _Alignment)
{
    void* pMemory = operator new[](_Size + _Alignment);
	memint BaseAdress = (memint)reinterpret_cast<size_t>(pMemory);
	
	uint8 Offset = static_cast<uint8>(BaseAdress % _Alignment);
	if (Offset == 0) Offset = _Alignment;
	
	uint8* pBytePtr = reinterpret_cast<uint8*>(pMemory);
	
	pBytePtr += Offset-1;
	*pBytePtr = Offset;
	++pBytePtr;
	
	return pBytePtr;
}

// -------------------------------------------------------------------------------------------------

//! /note	Like DeAllocAligned, only for arrays.
void ArrayDeAllocAligned(void* _pObject)
{
	uint8* pBytePtr = reinterpret_cast<uint8*>(_pObject);
	uint8 Offset = *(pBytePtr-1);
	pBytePtr -= Offset;
	
    operator delete[](pBytePtr);
}

// -------------------------------------------------------------------------------------------------

CB_SUBNAMESPACE_END